home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Taifun / Taifun 099 (1989-05-15)(Ossowski, Stefan)(DE)(PD).zip / Taifun 099 (1989-05-15)(Ossowski, Stefan)(DE)(PD).adf / PCQ / Pascal.doc < prev    next >
Text File  |  1989-03-31  |  49KB  |  1,167 lines

  1.  
  2.                         PCQ version 1.0
  3.             A very simple Pascal compiler for the Amiga
  4.                        by Patrick Quaid
  5.  
  6.  
  7.     PCQ (which stands for Pascal Compiler, um, Q ...  look, I
  8. couldn't come up with a name so I used my initials, OK?) is a modest
  9. Pascal sub-set compiler that produces assembly code.  It is not in
  10. the Public Domain (I retain the copyright to the source code, the
  11. compiler, the run time library source code, the run time library,
  12. and this documentation), but it can be freely distributed as long as
  13. all the files in the archive are included (with the possible
  14. exception of the assembler and linker) and unchanged.  The compiler
  15. is slow, and it can't handle a couple of things, but all in all it's
  16. worth the price.  To summarize:
  17.  
  18. The bad:
  19.  
  20.     The compiler is awfully slow.
  21.     It doesn't allow range types.
  22.     It doesn't support the 'with' statement or sets.
  23.     Multiplication and division are done the easy way, which
  24.        results in an odd mixture of 16 and 32 bit math.  This
  25.        will be fixed before the next release.
  26.     The code is not optimized at all.  It is, therefore, slow,
  27.        fat and generally silly looking.
  28.     Programs produced by PCQ can be run only from the CLI.
  29.        This will be fixed fairly soon.
  30.     The compiler gets knocked for a loop by most errors.
  31.  
  32. The good:
  33.  
  34.     It works, for the most part.
  35.     The compiler supports include files.
  36.     It allows for external references, although you have to
  37.        do the checking (this isn't Modula-2, after all).
  38.     It supports records, enumerated types, pointers, arrays,
  39.        and strings.
  40.     Type conversion as found in Modula-2 is supported.  In
  41.         other words, something like "integer('d')" is
  42.        legal.
  43.     You can have as many const, var, type, procedure and
  44.        function blocks as you want, in any order.
  45.     It's free.
  46.  
  47.  
  48.  
  49.  
  50.  
  51.          Table of Contents
  52.  
  53.  
  54.     This manual is intended to be read with a file reader or
  55. text editor, so this table of contents is based on line numbers
  56. rather than page numbers.
  57.  
  58.  
  59. Section                                Line number
  60.  
  61. How To Use PCQ  ........................   89
  62. An Explanation of Its Ills  ............  179
  63. Predefined Stuff  ......................  276
  64.     Constants  .........................  303
  65.     Types  .............................  340
  66.     Variables  .........................  380
  67.     Functions  .........................  396
  68.     Procedures  ........................  436
  69.     Extra Statements  ..................  479
  70.     The extra libraries  ...............  516
  71. Reserved Words  ........................  529
  72. Floating Point Math  ...................  555
  73. The Limits of PCQ  .....................  601
  74. Strings  ...............................  626
  75. Compiler Directives  ...................  676
  76. Type Conversions  ......................  718
  77. External References  ...................  761
  78. Input/Output  ..........................  842
  79. Errors  ................................  996
  80. Run Time Errors  ....................... 1022
  81. Sources  ............................... 1039
  82. Notes to Assembly Programmers  ......... 1083
  83. Improvements On The Burner  ............ 1098
  84. Other Notes, Copyright & My Address  ... 1123
  85.  
  86.  
  87.  
  88.  
  89.                         How To Use PCQ
  90.  
  91.  
  92.     There are several files in this archive you will need to
  93. copy over to your work disk.  The compiler (Pascal) is one, of
  94. course, as well as the run time library (called PCQ.lib- there's a
  95. readme file in the archive that explains all the file names, by the
  96. way).  If you do not have the assembler (A68k) and linker (Blink),
  97. you'll have to copy them as well (they might not have been included
  98. in this archive, but should be available on a local bulletin board
  99. or on Fred Fish disks).  These files are necessary for even the
  100. simplest compilations.
  101.  
  102.     The files with the suffix .p are example Pascal programs,
  103. which you can copy over if you want.  I spent a lot more time
  104. working on the compiler than on these examples, but a couple of them
  105. are interesting if you haven't seen programs like them before.  They
  106. demonstrate just about every aspect of the compiler that I could
  107. think of, so you should probably take a look at them and then get rid
  108. of them.
  109.  
  110.     The files that end with .i are include files for a few of
  111. system libraries.  They define the records, types, constants,
  112. procedures, functions and variables needed to access the system.
  113. These you probably should keep around.  There is also an include file
  114. for a few string routines.  The code related to all these routines is
  115. in the run time library.
  116.  
  117.     In order to compile a program, first write one.  Or use one
  118. of the example programs.  Then type:
  119.  
  120.              1> Pascal prog.p prog.asm
  121.  
  122.     'Pascal' is, of course, the name of the compiler.  You can
  123. change it if you want.  'Prog.p' is the pascal source file, which
  124. can also be called whatever you want.  The last word is the name of
  125. the assembly file produced.  At the moment these are the only
  126. command line arguments allowed.  By the way, the example programs
  127. assume that the include files are in a directory called "Include",
  128. which is actually a subdirectory of the current directory (in other
  129. words, the programs will try to include "Include/exec.i" instead of
  130. just "exec.i").  If this conflicts with your setup, just edit the
  131. include statements at the start of the file.  Assuming the
  132. compilation completes without any errors, you then type:
  133.  
  134.              1> A68k prog.asm prog.o
  135.  
  136.     This invokes the assembler to produce object code.  If the
  137. archive included A68k it probably also included the documentation for
  138. it, so read that for information about the assembler.  If the
  139. assembler was not included, get and use A68k by Charlie Gibbs,
  140. version 1.2.  A68k does lots of small scale optimization that the
  141. code from PCQ might very well depend upon, so I don't claim that the
  142. compiler works with any other assembler.  Finally, you want to link
  143. the program, so you type:
  144.  
  145.              1> Blink prog.o small.lib to prog library PCQ.lib
  146.  
  147.     This will produce a finished executable program called 'prog'.
  148. All of the Pascal run time routines, Amiga system routines, and my
  149. tiny little string library are contained in PCQ.lib.  If any of the
  150. routine names clash with ones you are working with, just be sure to
  151. put your library or object file in front of PCQ.lib on the Blink
  152. command line.  If Blink was included in the archive it's documentation
  153. probably was as well, so read that to answer any questions you may
  154. have about the link process.
  155.     I use Blink version 6.7, and again I assume that PCQ won't
  156. work with any other linker or version.  Small.lib is a library of
  157. addresses written by Matt Dillon.  Because of an apparent bug
  158. in Blink, it has to be included in the object files, rather
  159. than the libraries where it belongs.  It won't increase the
  160. size of your executable files, though.
  161.     Instead of all this business you could just use the 'make'
  162. script that's included in the archive.  You may have to change it
  163. around a bit so that it looks in the proper directories and whatnot,
  164. then through the magic of AmigaDOS 1.3 you should make it a script
  165. file.  Then you can invoke it like:
  166.  
  167.              1> make prog
  168.  
  169.     It will take the file 'prog.p' and produce the finished file
  170. 'prog'.  If your program has separately compiled units, you'll need
  171. to modify the batch file or write another.  I recommend writing a
  172. script file for any program you'll need to compile a few times.  If
  173. none of this makes any sense, write or call me and I'll try to give
  174. you more coherent instructions.
  175.  
  176.  
  177.  
  178.  
  179.                  An Examination of Its Ills
  180.  
  181.    I might as well get this over with right away.  As was
  182. mentioned earlier, sets and the 'with' statement do not work at all.
  183. Another thing that's not accepted is syntax like:
  184.  
  185.     type
  186.         smallnumber = 1..20;
  187.  
  188.     PCQ doesn't do any overflow checking of this sort during
  189. runtime, so this wouldn't mean much at the moment anyway.  The
  190. exception to this is in the declaration of arrays, where this syntax
  191. is accepted and in fact there is some range checking available.
  192. Read on for details.  Something else that won't work is this:
  193.  
  194.     type
  195.         WindowPtr = ^Window;
  196.         Window = record
  197.             NextWindow : WindowPtr;
  198.             ...
  199.  
  200.     It will fail on the first line with an 'Unknown ID' error. 
  201. Instead, use something like:
  202.  
  203.    type
  204.        Window = record
  205.            NextWindow : ^Window;
  206.            ....
  207.        end;
  208.        WindowPtr = ^Window;
  209.  
  210.     This is something I should get around to fixing, but it isn't
  211. strictly necessary, so there you go....
  212.     Also note that PCQ does not require, and in fact
  213. cannot accept, file variables in the Program statement at the
  214. beginning of a program.  In other words something like...
  215.  
  216.     Program Tester(input, output);
  217.  
  218.     ...is not allowed.  Just leave out everything in the
  219. parentheses, then leave out the parentheses.  PCQ assumes, at this
  220. point, that you will need both Input and Output.  Another feature of
  221. standard Pascal that I'm not too hot on including is the "goto"
  222. statement.  Although both "label" and "goto" are reserved words, I
  223. have not yet made them part of the language.
  224.  
  225.     Literal real numbers (like "10.0") are not yet allowed in
  226. PCQ.  In the next version real numbers will be more fully supported,
  227. but for now you must use the techniques described in the section
  228. "Floating Point Math".
  229.  
  230.     The compiler will not yet allow variant records.  This I will
  231. fix pretty soon, since the next version of the compiler will probably
  232. require them.  In character array constants, PCQ does not accept the
  233. two single quotes in a row that are supposed to signify one quote
  234. within the array.  Instead it offers you a different type that I'll
  235. get to in a moment.
  236.  
  237.     The compiler is written in PCQ Pascal, of course, and
  238. therefore exhibits some of its problems.  One of these is that,
  239. although integers are 32 bits long, the compiler will
  240. misunderstand any literal integer in the text of your program
  241. that is greater than about 100,000 (actually it's much more than this,
  242. but I figure this is easier to remember).  At this point it also cannot
  243. properly read and write them either.  This will be fixed when I
  244. add full 32 bit math support, but the temporary fix is to use
  245. hexadecimal numbers.  With these you can specify any 32 bit number,
  246. using the normal dollar sign followed by 0..9 or a..f or A..F syntax.
  247. If the compiler has to write a large number, it will use hexadecimal
  248. in order to these errors.
  249.  
  250.     Finally we get to nested procedures.  Because of two
  251. problems, I had long ago decided to leave them out.  Although I
  252. wrote most of the compiler with that in mind, in turns out that
  253. they almost work, so I guess I'll have to address them.  The
  254. first problem is with their names.  Using nested procedures in
  255. Pascal it is possible to have two procedures with the same name,
  256. but under different scopes.  This is fine as far as the compiler
  257. is concerned, but the assembler that takes over has only one
  258. scope.  Thus I should have made sure that the compiler produced
  259. unique names for each procedure and function.  This would have
  260. been easy enough to take care of, but like I said I didn't even
  261. consider the possibility.  Next time, definitely.
  262.  
  263.     The other problem is more complex than I really want to get
  264. into, but it boils down to this:  from a nested procedure, you
  265. cannot access the local variables of parent procedures.  You can
  266. access the procedure's own local variables, its parameters, and the
  267. variables global to the program.  Again the compiler will not
  268. complain (it is, after all, legal Pascal), but the program won't run
  269. right.  I know now how I'm going to take care of this, and it's
  270. fairly simple, but fixing it means a whole new round of testing so
  271. this release goes without it.
  272.  
  273.  
  274.  
  275.  
  276.                    Predefined Stuff
  277.  
  278.     I've arranged the predefined identifiers as they are supposed
  279. to appear in Pascal.  In PCQ, however, you can have these blocks
  280. in any order, and you can have more than one of each.  In other words,
  281. your program could look like:
  282.  
  283.    Program name;
  284.    var
  285.        variable declarations
  286.    type
  287.        types
  288.    var
  289.        more variables
  290.    procedure
  291.        a procedure
  292.    var
  293.        still more variables....
  294.  
  295.    And so on.  An identifier must still be declared before it
  296. is used, of course.  I allowed this because it is a real pain to
  297. arrange a bunch of different include files (each of the system
  298. include files would have had to be split into four sections : the
  299. constants, the types, the variables, and the procedures and
  300. functions).
  301.  
  302.  
  303. CONST
  304.  
  305.    True and False are defined as -1 and 0, respectively.
  306.    Nil is defined as a pointer with the constant value zero,
  307. but is not a reserved word as it is in standard Pascal.
  308.  
  309.    Most places the compiler requires a constant, it will take a
  310. constant expression (one that can be evaluated during the compile).
  311. For example, the following will work:
  312.  
  313.    const
  314.        first = 234;
  315.        second = first * 2;
  316.  
  317.    type
  318.        thetype = array [first .. first + 7] of char;
  319.  
  320.    Unfortunately you cannot yet use standard functions, type
  321. conversions, or other nifty things that you can do with expressions
  322. in the program body.  Just the five basic math functions (+, -, *,
  323. div, mod), for now.  Also note that 'first + 7' up there would be
  324. evaluated during the compile, but the same text in the body of the
  325. program would be evaluated during run time.  In other words, there
  326. is no such thing as constant folding yet.
  327.    When you are using integer constants, you can separate the
  328. digits with an underscore, similar to Ada.  In other words you
  329. could have:
  330.  
  331.    const
  332.        thousand = 1_000;
  333.        tenthousand = 1_0_0_0_0;
  334.  
  335.    MaxInt is defined as $7FFFFFFF, which comes out to something
  336. over two billion.  Don't try to write it.  MaxShort is 32767, or
  337. $7FFF in hex.
  338.  
  339.  
  340. TYPE
  341.  
  342.    There are several predefined types.  They include:
  343.  
  344. Integer      4 bytes, but only 16 bits of reliable range
  345.              when doing multiplication and division.  This
  346.              will be fixed.
  347. Short        2 bytes.  Literals within the program text are
  348.              assumed to be short values unless they are greater
  349.              than 32767 or less than -32767.
  350. Byte         1 byte.  These three types are all numeric types, so
  351.              you can use them in normal expressions without
  352.              worrying about type conversions.  The compiler
  353.              automatically 'promotes' the small values to
  354.              whatever size is required.  Remember that there is
  355.              currently no overflow checking.
  356. Char         1 byte.
  357. Boolean      1 byte.  False is 0 and true is -1.
  358. String       4 bytes.  Really just defined as '^char'.  I will
  359.              explain further in the section 'Strings'.
  360. Address      4 bytes.  This is a pointer to no particular type.
  361.              It is type compatible with any other pointer- in fact
  362.              the constant nil is of type Address.
  363. Text         18 bytes.  This is not the same as a 'file of
  364.              char'.  The standard input and output are Text
  365.              files.    You can read and write integers,
  366.              characters, arrays of characters, and strings
  367.              to Text files.  You can also write Boolean values.
  368. Enumerated   2 bytes.
  369.  
  370.    As was mentioned above, you can have arrays, pointers,
  371. records, and files based on the above types.  You can also have
  372. synonym types (like 'type int = integer;'), but they don't work very
  373. consistently.
  374.    Also note that almost anywhere you need a type, you can use
  375. a full type description.  Some compilers have a problem with
  376. this, and I'm not sure what Standard Pascal says about it, but
  377. then again I really don't care much.
  378.  
  379.  
  380. VAR
  381.  
  382.    The only standard variable included in PCQ is :
  383.  
  384.    CommandLine   : array [1..128] of char;
  385.  
  386.    As its name would indicate, this variable is initialized
  387. during the startup routine to whatever the CLI command line held. 
  388. It is an extra copy, so you can alter it as you wish.  The
  389. significant characters are terminated by a zero byte, after which
  390. it's anybody's guess as to what it contains.  After you have used
  391. the information from this array, or if you didn't need it in the
  392. first place, feel free to use the array for whatever you might need. 
  393. It's going to be there regardless (sorry about that), so you
  394. might as well get some use out of it.
  395.  
  396. FUNCTION
  397.  
  398.    The standard functions that do not concern real numbers are
  399. provided.  They include:
  400.  
  401.    function ord(x : any ordinal type): integer;
  402.       returns the ordinal position of the argument.
  403.  
  404.    function chr(x : numeric type) : char;
  405.       returns the indicated character.
  406.  
  407.    function abs(x : numeric type) : the same type;
  408.       returns the absolute value.
  409.  
  410.    function succ(x : ordinal type) : the same type;
  411.       returns x + 1, of the same type
  412.  
  413.    function pred(x : ordinal type) : the same type;
  414.       returns x - 1, in that type
  415.  
  416.    function odd(x : numeric type) : boolean;
  417.       returns true if the number is odd
  418.  
  419.    function eof(x : any file): boolean;
  420.       returns true if you are at the end of an input file.
  421.  
  422.    In addition to these standard standard functions, there is
  423. another standard function for this compiler in hopes of making it
  424. somewhat useful.  It is
  425.  
  426.    function adr(var x : any variable): Address;
  427.       returns the address of the variable in question.
  428.  
  429.    All the routines up to this point are handled in line.  The
  430. other two standard functions are for opening files.  They will be
  431. more fully explained when I get around to writing about
  432. input/output.  There is also a syntax like 'typename(expression)'
  433. supported by the language which looks like a function.  This will
  434. be explained in a later section called Type Conversions.
  435.  
  436. PROCEDURE
  437.  
  438.    The standard procedures are write, writeln, read, readln,
  439. get, new, dispose, exit, and trap.  The first five will be covered in
  440. the IO section.  The other four are:
  441.  
  442.    procedure new(var x : pointer variable);
  443.  
  444.    This allocates public memory the size of whatever type is
  445. pointed to, then puts the address into x.  PCQ allocates memory using
  446. Intuition's AllocRemember() routine, so that at the end of execution
  447. all the memory allocated through new() is returned to the system.
  448. This means that you don't absolutely have to call dispose() for every
  449. new(), although you should.  By the way, if the allocation fails, the
  450. program aborts (Sorry about that.  I'll change it eventually).
  451.  
  452.    procedure dispose(var x : pointer variable);
  453.  
  454.    This returns the allocated memory to the system.  If
  455. something got confused, and you try to dispose of memory you
  456. never allocated, this will just return.  Unfortunately that means
  457. you may never diagnose a problem in your program, but at least it
  458. won't be calling the Guru all the time.
  459.  
  460.    procedure exit(error : integer);
  461.  
  462.    Exit() aborts a program early.  It is the acceptable method
  463. of escaping a program.  It does the same stuff that the program
  464. normally does when it quits, then returns the error number you give
  465. it to AmigaDOS.  This routine will free all the memory and close the
  466. open files.  By the way, the error number should be zero if the
  467. program terminated correctly, 5 for a warning, 10 for an error, and
  468. 20 for a catastrophic error.
  469.  
  470.    procedure trap(num : integer);
  471.  
  472.    The argument for this procedure must be a constant
  473. expression, although the type doesn't matter.  All it does is insert
  474. a 68000 trap instruction into the code at the point of the statement.
  475. This is useful for the debugger I use, and for nothing else I can
  476. imagine.  It effectively inserts a break point in the program.
  477.  
  478.  
  479. Extra Statements
  480.  
  481.    First of all, PCQ supports if, while, repeat, for and case
  482. statements.  It does not yet support 'with' statements, but it will
  483. soon enough.
  484.    The if, while and repeat statements work pretty much like
  485. they should.  The case statement is a bit weak.  First of all, the
  486. individual cases must be constants.  Unfortunately there can
  487. currently only be single cases- in normal Pascal you can list
  488. several cases separated by commas and use ranges.  Soon you'll be
  489. able to do both, but not yet.  The syntax for the case statement
  490. looks informally like:
  491.  
  492.    case <ordinal expression> of
  493.        <constant expression> : <statement>;
  494.        <constant expression> : <statement>;
  495.       ...
  496.    end;
  497.  
  498.    ...where each <constant expression> is of the same type as
  499. the <ordinal expression>.
  500.    The for statement supports 'downto', which changes the
  501. increment from 1 to -1.  It also supports 'by', which allows you to
  502. set the increment.  The argument for the 'by' part can be any
  503. regular expression, but for any negative increment you must use
  504. 'downto' rather than 'to', or the loop will only run once.  By the
  505. way, for loops always run at least one time.  Anyway the syntax
  506. looks something like:
  507.  
  508.       for <variable> := <expression> to|downto <expression>
  509.                         [by <expression>] do <statement>;
  510.  
  511.    The other statement included is 'return', which simply
  512. aborts a PROCEDURE early.  You can abort a FUNCTION early by
  513. assigning the function name to some value, so 'return' works only in
  514. procedures.
  515.  
  516. The extra libraries
  517.  
  518.    There should be some extra libraries included in the archive
  519. (the code for the libraries is in PCQ.lib, but there should be
  520. include files describing them).  Most of these libraries are
  521. interfaces to the system, and all of them are individually documented
  522. in their .i files.  Note that to use Intuition, Exec, AmigaDOS or
  523. basic floating point math functions you will NOT need to open the
  524. associated libraries.  All these libraries are opened during the
  525. start sequence, and they are in fact required by all PCQ programs.
  526.  
  527.  
  528.  
  529.                       Reserved Words
  530.  
  531.    The reserved words of PCQ are as follows:
  532.                             
  533.             and         for         procedure
  534.             array       forward     program
  535.             begin       function    record
  536.             by          goto        repeat
  537.             case        if          return
  538.             const       in          set
  539.             div         label       then
  540.             do          mod         to
  541.             downto      not         type
  542.             else        of          until
  543.             end         or          var
  544.             external    packed      while
  545.             file        private     with
  546.  
  547.    As you can see, even the unimplemented stuff is reserved.  The
  548. only one that is not explained somewhere in this document is
  549. "private", which is one of the things that will help make external
  550. references and modularity more flexible in version 1.1.
  551.  
  552.  
  553.  
  554.  
  555.                      Floating Point Math
  556.  
  557.    First of all, real numbers are not fully integrated into the
  558. language.  They can be used, but you have to do some extra work.
  559. Real math is based on the MathFFP.library, which is one of the
  560. libraries that is in memory.  The main reason I haven't fully
  561. included real numbers, by the way, is because I am looking for some
  562. feedback concerning the awkwardness this approach.
  563.  
  564.    The way you carry out floating point math is to make calls
  565. to the library.  At the top of your program you must include
  566. "Math.i", which will declare all the functions from mathffp.library.
  567. You will not have to open the library, however.  In any case, in
  568. order to do "f1 := f1 + f2", you use:
  569.  
  570.       f1 := spadd(f1, f2);
  571.  
  572.    Read "Math.i" for a list of the functions.  In the example
  573. programs there is a file called RealIO.p which has routines to read
  574. and write real values to and from files and standard IO.
  575. Incidentally, the way to specify a literal real value (since you
  576. can't write something like "10.0") is to use spfloat().  For example
  577. to specify 4.546, you would write:
  578.  
  579.       spdiv(spfloat(4546),spfloat(1000))
  580.  
  581.    This is slow, and involves no less than three calls
  582. to the real numbers library, but that is so far the only way to do
  583. it.
  584.  
  585.    The next version of the compiler will have fully integrated
  586. real numbers.  In other words you'll be able to specify literal
  587. values, do simple math, and carry out IO on them.
  588.  
  589.    Functions like sin(), cos(), and sqrt() are not handled by
  590. mathffp.library.  They are located in mathtrans.library, which is
  591. disk based.  Thus whenever you write a program that needs these
  592. functions, the system disk will have to be inserted in order to get
  593. to LIBS:.  Read MathTrans.i for further information about all this.
  594. By the way, I have no plans to implement these functions in any
  595. other fashion.  In the forseeable future you'll need
  596. MathTrans.library every time you need trigonometric or exponential
  597. functions.
  598.  
  599.  
  600.  
  601.                      The Limits of PCQ
  602.  
  603.    The compiler can accept lines of any length, although it
  604. will display at most the previous 128 characters read in if an error
  605. occurs.  As far as the size of the file is concerned, it can be any
  606. length (the only part of the file that is in memory at any time is
  607. the current character), with, of course, a few caveats.  The first
  608. is that, since this version of the compiler still uses a big array
  609. to hold identifiers, there is a limit to the total number you can
  610. have.  Don't worry about that though:  all of the include files
  611. combined only take up about half the room.  This will be fixed in
  612. the next version.  There are other fixed limits in the compiler, but
  613. I never got anywhere near them in compiling the compiler, so I can't
  614. imagine you'll hit them.
  615.    The other limit is that, since the compiler produces lots of
  616. assembly code output, there must be room on the disk for the whole
  617. file.  The assembly output is, as a rule of thumb, as much as five
  618. times as large as the Pascal source.
  619.    One dubious advantage of using mostly fixed amounts of memory
  620. is that I can tell you that the compiler takes up just under 150k in
  621. memory, so with its stack and the rest of incidental memory it should
  622. require about 160 or 170k to run.
  623.  
  624.  
  625.  
  626.                            Strings
  627.  
  628.    As was mentioned above, strings should be thought of like
  629. '^char'.  They are defined that way, but also are given special
  630. properties.  They can be dynamically created, sized, and disposed
  631. of.  A string is supposed to be terminated by a zero byte, so if
  632. you write any string handling routines be sure you follow that
  633. convention.  Otherwise you'll confuse all the other string
  634. routines.  In the text of a program, you delineate strings with
  635. double quotes, instead of the single quotes found around normal
  636. arrays of char.  Thus:
  637.  
  638.    "A string"   is indeed a string, while
  639.    'not one '   is considered an array [1..8] of char.
  640.  
  641.    The other interesting thing about strings is that they can
  642. have C-like escape sequences.  What happens is that you type a
  643. backslash (looks like this: \), and the very next character is
  644. specially handled.  C has a bunch of these things, but I have, so
  645. far, included only the ones I use, which are:
  646.  
  647.    \n   which stands for a line feed, chr(10)
  648.    \t   which stands for a tab, chr(9)
  649.  
  650.    Everything else passes through unchanged, so that you can
  651. also use this mechanism to include double quotes in your strings. 
  652. And you have to use it to include backslashes.  What this all
  653. boils down to is that the string "A\tboy\nand\\his \"dog.\""
  654. prints out like:
  655.  
  656.       |A       boy
  657.       |and\his "dog"
  658.  
  659.    There is something called StringLib.i in this archive that
  660. declares a few string handling routines - the ones I needed for
  661. the compiler.  Read that file for more information.  And if you
  662. get confused about strings, just remember that they're pretty much
  663. like C strings, and can be used in most of the same situations.
  664. Remember that if you declare a string you don't get any space for
  665. the characters.  All you get is space to hold the address of where
  666. the characters are, so you have to call AllocString() in StringLib
  667. or something like it to get some room to work.  If you are a BASIC
  668. programmer you might run into some difficulty on this subject, and
  669. I would suggest reading up on C strings in hopes that whatever you
  670. read can explain the situation better than I.
  671.    By the way, note that 'stringvar^' is valid, and is of type
  672. 'char'.
  673.  
  674.  
  675.  
  676.                    Compiler Directives
  677.  
  678.    Eventually there will be billions of compiler directives,
  679. but for now there are just three.  Compiler directives work like
  680. this:  if the first character in a comment is the dollar sign ($),
  681. the compiler looks to the next character for a command.  No spaces
  682. are allowed between the bracket, dollar sign, and command character.
  683. The compiler directives are:
  684.  
  685. {$I "fname"}   This will insert the file "fname" into the
  686.                stream at this point.  When it has finished,
  687.                it will end the comment (no more directives
  688.                allowed in this comment) and continue on. 
  689.                There can be any amount of white space in
  690.                front of the filename and anything you want,
  691.                such as the rest of a comment, after it. The
  692.                filename is a string, so it must be in
  693.                quotes.  Several of the example programs should
  694.                demonstrate the include syntax.
  695.  
  696. {$A            This directive inserts assembly instructions
  697. Instructions   into the assembly file produced by the compiler.
  698. }              Look at the assembly language produced by the
  699.                compiler to figure out how to reference variables
  700.                and subroutines.  This directive simply passes
  701.                everything from after the A until, but not including,
  702.                the closing bracket.  You should therefore include
  703.                comments in assembly fashion.
  704.  
  705. {$R+} or       The '+' directive instructs the compiler to produce
  706. {$R-}          range-checking code for arrays.  From this point
  707.                until the compiler reaches a {$R-} directive, each
  708.                array access will check that the index value is
  709.                within the bounds of the array.  This expands and
  710.                slows the code, so I recommend only doing this
  711.                during testing.  If the index is out of bounds, the
  712.                program will abort with an error code (look at the
  713.                section "Run Time Errors" for more information).
  714.  
  715.  
  716.  
  717.  
  718.                       Type Conversions
  719.  
  720.    If you have used Modula-2, you can skip this section.  In
  721. writing the compiler I found the need to cheat a bit on type
  722. checking, so I decided to use Modula-2's syntax for changing the
  723. type of an expression.  What you do is use the name of the type
  724. as if it were a function.  The expression in the parentheses is
  725. evaluated, and the result is considered to be of the type named. 
  726. It goes like this:
  727.  
  728.    IntegerVariable := integer(any ordinal expression);
  729.    CharVar := char(456 - 450);
  730.    if boolean('r') then ....
  731.  
  732.    This works not only for the included standard types, but
  733. also for any type you create.  Thus this is also legal:
  734.  
  735.    type
  736.        charptr = ^char;
  737.    var
  738.        charvar : charptr;
  739.    ....
  740.        charvar := charptr(0);
  741.        charvar := charptr(integer(charvar) + 1);
  742.  
  743.    Note that the type must be named in order for this to work. 
  744. Something like...
  745.  
  746.    variable := array [1..4] of char(expression())
  747.  
  748.    ...will not work.  This then is the only case where a type
  749. is possible, but you can't use a complete type definition.  I'm
  750. pretty sure you can in all other cases, but what do I know....
  751.    Note further that not all type conversions are valid.
  752. Converting a type to one of a different size is often a bad idea, as
  753. is converting a structured type (array or record) to a simple type.
  754.    I should probably warn you against the indiscriminate use of
  755. these, but what the heck.  Have a ball.
  756.  
  757.  
  758.  
  759.  
  760.  
  761.                     External References
  762.  
  763.    First a little background.  The source code for this
  764. compiler is, in total, about 70k.  The assembly listings produced by
  765. the compiler generally expand the Pascal source about five times, so
  766. you can see that if I decided to write the compiler as one big
  767. program, it would be way too unwieldy.  What I needed was a facility
  768. for separate compilation.  What I came up with was this:  if you
  769. have a previously compiled procedure somewhere that you want to call
  770. from the Pascal program, just make it a forward declaration
  771. somewhere before you use it.  If the compiler gets to the end of
  772. your program and has not yet run across the full definition of a
  773. forward declared procedure, it assumes it's an external reference
  774. and makes the appropriate statements in the assembly file.  So it
  775. looks like this:
  776.  
  777.    procedure DrawMap;
  778.        forward;
  779.  
  780.    As long as you don't have something else defined as DrawMap,
  781. the compiler will produce an external reference to _DrawMap (note
  782. the underscore prepended to the name).
  783.  
  784.    Now for something somewhat less kosher.  I needed some
  785. syntax to allow the external routines to access the same global
  786. variables as the main file.  What I came up with is a different
  787. file format.  Whereas the normal Pascal file looks like:
  788.  
  789.       program Name;
  790.       declarations
  791.       procedures and functions
  792.       begin
  793.           main program
  794.       end.
  795.  
  796.    The external file looks like this:
  797.  
  798.       external;
  799.       declarations (like normal)
  800.       procedure and functions (like normal)
  801.  
  802.    There are three things to note.  The first is that there is
  803. no main program, the second that there is no special ending
  804. syntax.  It is just a bunch of procedures and functions in a row
  805. until the end of the file.  The other thing is that any variables
  806. declared at the global, or outermost, level are considered
  807. external references.  In the source for the compiler there is a
  808. file that has just the global variable declarations.  This file
  809. is included by all ten of the source files, but only the main
  810. file produces storage space for them.  The other nine just
  811. produce external references.
  812.  
  813.    I guess this is a good time to discuss a couple of issues
  814. related to using an assembler with the separate compilation deal. 
  815. First, note that all procedure, function and variable names are
  816. offered as external references by the module in which they are
  817. defined.  If an outside routine wants to use any of these values,
  818. it should be looking for something starting with an underscore
  819. and spelled the same as the first time the word is encountered in
  820. the program.  Pascal is case insensitive, of course, but I can't
  821. help the assembler and linker.  Also remember that there is no
  822. type checking across files (again, get Modula-2 if you want that
  823. sort of stuff).  This means that a procedure that expects a
  824. string might be sent a Boolean value, which would probably
  825. conjure the Guru.
  826.    The other thing to note is that this compiler pushes
  827. procedure and function arguments on the stack from left to right.
  828. Most C compilers (including Lattice and PDC) do it the opposite way.
  829. Draco also does it left to right.  This doesn't mean that you can't
  830. use code and libraries from them - it simply means that you should
  831. reverse the order of the arguments.
  832.    Just two more notes on this subject:  first, the compiler
  833. considers registers d0, d1, d2, a0, and a1 fair game, and will
  834. destroy them at will.  d2 might be a problem, but the others
  835. shouldn't.  For further information, just look at the assembly code
  836. produced.  The second note is just a reminder to anyone who might
  837. want to link Pascal programs to other languages:  remember what
  838. 'var' does before a variable, and be sure to use it correctly.
  839.  
  840.  
  841.  
  842.                       Input/Output
  843.  
  844.  
  845.    There are several routines for handling IO in PCQ.  Before I
  846. get to them, however, let me discuss what happens when you open a
  847. file.  The actual file variable you declare in the program, as in:
  848.  
  849.       var
  850.           filevar : file of integer;
  851.  
  852.    is actually something like a record, which would look like
  853. this:
  854.  
  855.    file = record
  856.        FileHandle   : a DOS file handle
  857.        Buffer       : a pointer to the input buffer
  858.        Size         : the size of the elements of the
  859.                       file
  860.        EOF          : a Boolean value
  861.        IN/OUT       : (input, output)
  862.        NextFile     : a pointer to the next file record
  863.    end;
  864.  
  865.    Now you can't actually access these fields, but nonetheless
  866. 18 bytes of memory is reserved.  When you open a file, all of the
  867. fields are initialized as necessary, and the first element is
  868. read into the buffer.  The buffer is accessed by the filevar^
  869. syntax.  Also note that if the size of the elements of the file
  870. is greater than 4, or if it's 3 (don't ask), the program will
  871. allocate memory for a buffer.  This will be pointed to by the
  872. variable Buffer in this record.  If the size is 1, 2 or 4 (as in
  873. the case with chars, shorts and integers, respectively), the
  874. program will instead use the variable Buffer as the buffer, thus
  875. saving a little memory and time.  Filevar^ will always properly
  876. access the buffer whatever it is.
  877.    If at the end of execution there remain some open files, the
  878. shut-down code will close them for you.  This is only true for
  879. files opened through Pascal, using one of the open() routines
  880. explained below.  Anything you open directly through AmigaDOS is
  881. your own responsibility.
  882.  
  883.    The routines that handle file IO are these:
  884.  
  885.    function open(filename : string;
  886.                  filevar : file of something, or Text):boolean;
  887.  
  888.        This opens a file for writing.  If the file was there
  889.     before, this routine will erase it.  If everything worked
  890.     OK, it will return true.  If not, of course, it's false.
  891.  
  892.    function reopen(filename : string;
  893.                    filevar : file of something, or Text) : boolean;
  894.  
  895.        This is analogous to open() except it opens an existing
  896.    file for reading.
  897.  
  898.    The rest of the routines are the same as most Pascals.  Just
  899. for the sake of completeness, however, they are:
  900.  
  901.    write()      Write the stuff to a file or to standard out
  902.  
  903.    writeln()    Do the same as write, then output a line
  904.                 feed.  This only makes sense for Text files.
  905.  
  906.    read()       Read some stuff from a file or standard in.
  907.                 read(filevar, x) mimics...
  908.                     x := filevar^;
  909.                     get(filevar);
  910.                 ...just like most Pascals.  In this case, it
  911.                 mimics it very closely.
  912.  
  913.    readln()     Do read then keep reading until you hit a
  914.                 line feed.  This too only makes sense for
  915.                 Text files.
  916.  
  917.    get()        Reads the next file element from the file
  918.                 into the buffer.
  919.  
  920.     If the first argument of a read or write is a file variable,
  921. the input or output is from a file rather than the console or
  922. whatever.  That, of course, is normal Pascal, and looks like:
  923.  
  924.     writeln(outfile, 'The result is ', 56 div 4);
  925.  
  926.     Field widths are supported, but must be a constant
  927. expression.  What this means is that something like...
  928.  
  929.     writeln((67 * 32) + 5:10);
  930.  
  931.     ...  will print the result right justified in a field of ten
  932. characters, with spaces padding out the area to the left.  If you
  933. specify a field width lower than the width of the number, the number
  934. is printed in as few characters as possible.  Valid values for the
  935. field width are greater than or equal to one and less than MaxShort.
  936. You can specify a field width for any type in a write statement,
  937. although only when writing to a text file.
  938.  
  939.     Just for the sake of precision, I'll go over the delimeters
  940. for IO on Text files with various types:
  941.  
  942.     Write Char
  943.         Writes one character.
  944.     Write Boolean
  945.         Writes TRUE or FALSE, with no extra spaces.
  946.     Write Integer
  947.         Writes the number with no extra spaces, but
  948.         possibly a negative sign
  949.     Write Array of Char
  950.         writes the entire array, from first element to last.
  951.     Write String
  952.         Writes from the first character up to but not
  953.         including the zero byte.
  954.     Writeln
  955.         Writes a single EOLN (chr(10)) to the file.
  956.  
  957.     Read Char
  958.         Reads the next char.
  959.     Read Boolean
  960.         Can't do it.
  961.     Read Integer
  962.         This eats spaces and tabs until it meets up with
  963.         something else, then eats digits until it comes
  964.         upon a non-digit.  It does not eat that last non
  965.         digit.  If the routine runs across an EOLN before
  966.         it gets to the first digit, it returns zero.  If
  967.         it finds letters before it finds digits, it returns
  968.         zero also.
  969.     Read Array of Char
  970.         Reads characters into the array until either the
  971.         array is full or the routine finds an EOLN.  If it
  972.         finds an EOLN it will not eat it, so you'll have to
  973.         do that with a readln if you want.  If it returns
  974.         because of an EOLN it will also pad the rest of the
  975.         array with spaces.
  976.     Read String
  977.         Reads characters until it gets an EOLN.  The EOLN
  978.         is left in the input stream, and a zero is put in
  979.         its place in the string.  Note that this routine
  980.         does not check for length, so you must be sure that
  981.         your string can handle the longest line it might
  982.         encounter.
  983.     Readln
  984.         Reads characters up to and including the next EOLN.
  985.  
  986.    Also remember eof(filevar), from the functions, and note
  987. that there is no put() analogous to the get() routine.  For
  988. examples of all of these, look at the example programs.  Also
  989. note that the filevar^ sort of syntax is present.  Look at a
  990. Pascal text to understand it (I don't think Turbo Pascal uses
  991. this, so it might be Greek to a lot of Pascal programmers).
  992.  
  993.  
  994.  
  995.  
  996.                        Errors
  997.  
  998.    As I mentioned somewhere above, most errors will completely
  999. confuse the poor compiler, which will then start spewing out
  1000. errors that don't really exist.  It can get by a couple of
  1001. errors- for example if you leave out a semicolon somewhere, you
  1002. should get an error message but everything else should compile. 
  1003. Very few other errors will work that well.  I hope to make the
  1004. compiler a bit friendlier, but in the meantime the compiler will
  1005. abort the compile if it gets more than 5 errors.  I put this in
  1006. because the compiler will sometimes get one error, then start
  1007. producing errors on every symbol, and even get hung up on a
  1008. symbol.  Really ugly.
  1009.    If an error occurs, the compiler will write out at most the
  1010. two lines leading up to the error, and highlight the part that
  1011. it's currently working on.  The error probably occured either at
  1012. the highlighted symbol or just before it.  Also note that the
  1013. highlighted symbol is always the last symbol written (when the
  1014. symbol is just some punctuation, it can be difficult to see that
  1015. it is highlighted).  On the next line is the line number of the
  1016. error and the explanation of the error.  Currently I'm using text
  1017. descriptions of the errors, so there are no error numbers.
  1018.  
  1019.  
  1020.  
  1021.  
  1022.                     Run Time Errors
  1023.  
  1024.    A couple of things cause run time errors.  The few that are
  1025. handled at the moment are:
  1026.  
  1027.       Error   Explanation
  1028.  
  1029.         50    No memory for new()
  1030.         51    Divide by zero with Floating point numbers.
  1031.         52    Array access out of range.
  1032.  
  1033.    The error number is returned (through the exit() function) to
  1034. AmigaDOS.  If the program is running in a batch file you'll get to
  1035. see the return code.  I hope to have the run time system better
  1036. thought out in the next version of the compiler, so these might go.
  1037.  
  1038.  
  1039.                        Sources
  1040.  
  1041.    Like I said, I wrote this for the learning experience.  Some
  1042. of the places I went for information are:
  1043.  
  1044. 1.   PDC, a freely distributable C compiler supported by Jeff
  1045.      Lydiatt.  This is a very good program, and one of the best
  1046.      freely available compilers for the Amiga (the other really
  1047.      good one is Draco by Chris Gray).  I learned (and used) a
  1048.      lot about activation frames from the listings produced by
  1049.      this compiler.  Looking at the assembly code produced by
  1050.      this compiler was also my inspiration for starting to
  1051.      write a compiler.
  1052.  
  1053. 2.   Pascal-S, the Pascal compiler produced out of ETH Zurich.
  1054.      I got some ideas about the structure of a compiler from
  1055.      this, but not too many.
  1056.  
  1057. 3.   Small-C, another freely distributable C compiler.  This one
  1058.      is not nearly as powerful as PDC, but its simplicity helped
  1059.      me understand a thing or two.  Probably the best compiler
  1060.      source code that I found to learn from.  This and PDC were
  1061.      the compilers I used before this compiler was able to
  1062.      compile itself.  Many aspects of the design of PCQ come
  1063.      from Small-C.
  1064.  
  1065. 4.   Brinch Hansen on Pascal Compilers, by Per Brinch Hansen. 
  1066.      This book was of some use, which is more than I can say
  1067.      about the other half dozen I read while writing this.  From
  1068.      this book I mainly learned about all the things I was doing
  1069.      wrong.  Great.
  1070.  
  1071.    If you like the idea of freely distributable compilers, please
  1072. be sure to check out Draco from Chris Gray (on Fred Fish 76 & 77) and
  1073. PDC from Jeff Lydiatt (an old version is on Fred Fish 110).  Both are
  1074. much better products than PCQ and even rival the commercial compilers.
  1075. I'm not sure what a good source for the newer version of PDC would be -
  1076. perhaps you could write to Jeff (it's certainly worth it.  PDC has a
  1077. full preprocessor, a 'cc' front end, very fast optimized code ...
  1078. the works).  The syntax of Draco, by the way, is fairly similar to
  1079. Pascal.
  1080.  
  1081.  
  1082.       
  1083.                  Notes to Assembly Programmers
  1084.  
  1085.    During the course of a program PCQ uses registers d0, d1, a0
  1086. and a1 as scratch.  It also uses d2 and d3 during IO calls and d2
  1087. when comparing or assigning large data structures.  a7 is, of
  1088. course, the stack pointer, and I use a5 as the frame pointer.  a6 is
  1089. used to hold the library base during any call to the system, and a4
  1090. is reserved for future use (for accessing local variables of a
  1091. parent procedure).  The other registers are free, and in fact the
  1092. scratch registers should be free for you to use between statements.
  1093. After all, the compiler does no optimizing.
  1094.  
  1095.  
  1096.  
  1097.  
  1098.           Improvements On The Burner
  1099.  
  1100.    Version 1.1 of this compiler will definitely have:
  1101.  
  1102.    Full 32 bit math.
  1103.    Fully integrated floating point math.
  1104.    Properly implemented nested procedures.
  1105.    No more fixed arrays in the compiler itself.
  1106.    The ability to work with the Workbench.
  1107.  
  1108.    As far as the various other problems go, my main concern is
  1109. fixing bugs.  Rather far down on the list is adding every last detail
  1110. of Pascal.  Way down at the bottom of the list is code optimization.
  1111.    As far as gimmicks go, I'd like to integrate the compiler with
  1112. CygnusEd Professional (the editor I use) through the editor's Arexx
  1113. port.
  1114.    Version 1.1, with the improvements listed above and possibly
  1115. others, will be released during the summer of '89 at the latest.
  1116.    Any lettered version, eg version 1.0b, will be a bug fix.
  1117. I hope I don't run out of letters.  Increments in the tenths place
  1118. will indicate added functionality.  If I come out with 2.0 it will
  1119. be Modula-2.  3.0 will be Ada.
  1120.  
  1121.  
  1122.  
  1123.             Other Notes, Copyright & My Address
  1124.  
  1125.    As I mentioned above, this documentation, the source code
  1126. for the compiler, the compiler itself, the source code for the run
  1127. time library, and the run time library itself, are all (ahem):
  1128.  
  1129.    Copyright (c) 1989 Patrick Quaid.
  1130.  
  1131.    I will allow the package to be freely distributed, as long
  1132. as all the files in the archive, with the possible exception of
  1133. the assembler and linker (please include them if at all possible),
  1134. are included and unchanged.  Of course no one can make any real
  1135. money for distributing this program.  It may only be distributed
  1136. on disk collections where a reasonable fee is charged for the disk
  1137. itself.  A reasonable fee is defined here as the greater of $10
  1138. per disk, whatever Fred Fish is currently charging.  Sorry about
  1139. being repetitive, but I imagine it's best to state these things
  1140. clearly.
  1141.     Feel free to mess around with the compiler source code.  If you
  1142. make any substantial improvements, I would appreciate a copy of
  1143. them so that they can be incorporated into the next version if
  1144. appropriate.  If you make improvements that are not along the lines
  1145. of standard Pascal or the path indicated above, please don't
  1146. distribute your program under the name PCQ.  That would only
  1147. confuse things.
  1148.     This is not a shareware package.  Feel no guilt about using
  1149. it without paying for it.  The one payment I would really appreciate
  1150. is if you could let me know about bugs you discover (not
  1151. unimplemented features- I know about them.  I'm not trying to write
  1152. the end-all greatest compiler, but I do want it to be correct).  If
  1153. you have an overwhelming urge to give money away, please send a
  1154. donation to Charlie Gibbs, who wrote the assembler, and the Software
  1155. Distillery, who wrote the linker.
  1156.  
  1157.    Any questions, comments, or whatever can be addressed to:
  1158.  
  1159.       Pat Quaid
  1160.       8320 E. Redwing
  1161.       Scottsdale, AZ 85253
  1162.  
  1163.       (602) 948-8325
  1164.  
  1165.    Enjoy the compiler.  If you have any complaints, remember
  1166. what you paid for it.
  1167.